<?php

/**
 * Db模块，采用PDO
 * @property Redis $_redis Description
 */
class Db {
    // db
    private $db;
    // memcached
    public $memcached = false;
    // single instance
    private static $instance = false;
    // file cache
    public $fileCache = true;
    // file cached
    public $fileCached = false;
    // global cache
    public $cache = true;
    // debug
    public $debug = false;
    // config
    public $config;

    /**
     * @param $config
     * @return bool|Db
     */
    public static function get_instance($config) {
        if (!self::$instance) {
            self::$instance = new Db($config);
        }
        return self::$instance;
    }

    /**
     * Db constructor.
     * @param bool|false $config
     * @throws Exception
     */
    public function __construct($config = false) {
        if (!$config) {
            throw new Exception('配置文件有误');
        } else {
            $this->config = $config;
            try {
                $this->db = new PDO(sprintf("mysql:host=%s;dbname=%s", $config['db_host'], $config['db_name']),
                    $config['db_user'], $config['db_pass'], [
                        PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8;"
                    ]);
            } catch (Exception $ex) {
                throw new Exception('数据库连接失败！请检查扩展PDO是否打开或者配置文件中账号密码是否正确！');
            }
        }
    }

    /**
     * @param string $statement
     * @param int $fetchStyle
     * @return array
     * @throws Exception
     */
    public function query($statement, $fetchStyle = PDO::FETCH_OBJ) {
        try {
            if (preg_match("/INSERT/is", $statement)) {
                // INSERT
                if(!$this->db->exec($statement)){
                    throw new Exception($this->db->errorInfo()[2]);
                } else {
                    $result = $this->db->lastInsertId();
                }
            } else if (preg_match("/UPDATE|DELETE|REPLACE/s", $statement)) {
                // UPDATE|DELETE=
                $result = $this->db->exec($statement);
            } else {
                $result = $this->rawQuery($statement, $fetchStyle);
            }
            if ($this->db->errorCode() != '00000') {
                // 记录数据库执行日志
                throw new Exception($this->db->errorInfo()[2]);
            }
        } catch (Exception $ex) {
            Helper::log('db_query_error:' . $ex->getMessage());
            throw $ex;
        }
        return $result;
    }

    /**
     * 直接执行SQL语句
     * @param string $statement
     * @param int $fetchStyle
     * @return array
     */
    private function rawQuery($statement, $fetchStyle) {
        $query = $this->db->prepare($statement);
        $query->execute();
        return $query->fetchAll($fetchStyle);
    }

    /**
     * 查询一个数据
     * @param string $SQL
     * @return string
     */
    public function getOne($SQL, $cache = true) {
        $ret = $this->query($SQL, $cache);
        if (!$ret[0]) {
            return false;
        }
        return current($ret[0]);
    }

    /**
     * 查询一行数据
     * @param string $SQL
     * @return array
     */
    public function getOneRow($SQL, $cache = true) {
        $ret = $this->rawQuery($SQL, PDO::FETCH_OBJ);
        if ($ret) {
            return current($ret);
        }
        return false;
    }

    /**
     * 检查某字段有某值
     * @param string $table
     * @param string $field
     * @param string $value
     * @return bool
     */
    public function isExist($table, $field, $value) {
        $rst = $this->query("SELECT * FROM `$table` WHERE `$field` = '$value' LIMIT 1");
        return count($rst) > 0;
    }

    /**
     *
     * @param type $statement
     * @return type
     */
    public function exec($statement) {
        return $this->db->exec($statement);
    }

    /**
     * 使用事务
     * @return bool
     */
    public function transtart() {
        $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        return $this->db->beginTransaction();
    }

    /**
     * 提交事务
     * @return bool
     */
    public function transcommit() {
        return $this->db->commit();
    }

    /**
     * 回滚事务
     * @return bool
     */
    public function transrollback() {
        return $this->db->rollBack();
    }

}

class Helper {
    /**
     * Logger to file
     * @param string $message
     */
    public static function log($message) {
        $logDir = __DIR__ . DIRECTORY_SEPARATOR . 'errlog' . DIRECTORY_SEPARATOR . date('Y-m') . '/';
        if (!is_dir($logDir)) {
            mkdir($logDir, 0755, true);
        }
        if (!is_writable($logDir)) {
            chmod($logDir, 0755);
        }
        error_log(date('Y-m-d H:i:s') . ': ' . $message . PHP_EOL, 3, $logDir . date('Y-m-d') . '.txt');
    }
}